"use strict";
var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        if (typeof b !== "function" && b !== null)
            throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
/*class Logger {
    private static log = null;
    info() {
        console.info();
    }
    
    log() {
        console.log();
    }
    warm() {
        console.warm();
    }
    error() {
        console.error();
    }
    private getTime() {
        return new Date();
    }
    static get logger() {
        if(log === null) {
            log = new Logger();
        }
        return log;
    }
}*/
// BroadcastChannel封装，bc是半工
var Broadcast = /** @class */ (function () {
    function Broadcast(name) {
        this.ns = name;
        this.bc = new BroadcastChannel(name);
        var _this = this;
        this.bc.onmessage = function (data) {
            _this.receive(data.data);
        };
    }
    Broadcast.prototype.send = function (data) {
        this.bc.postMessage(data);
    };
    Broadcast.prototype.receive = function (data) {
    };
    Object.defineProperty(Broadcast.prototype, "name", {
        get: function () {
            return this.ns;
        },
        enumerable: false,
        configurable: true
    });
    return Broadcast;
}());
// 消息广播,基于事件分发 无需响应
var MessageBroadcast = /** @class */ (function (_super) {
    __extends(MessageBroadcast, _super);
    function MessageBroadcast(name) {
        var _this_1 = _super.call(this, name) || this;
        _this_1.dom = document.createElement("div");
        // 设置绑定类型，一个channel只能发送或者接收
        _this_1.type = null;
        return _this_1;
    }
    MessageBroadcast.prototype.bindingtype = function (type) {
        if (this.type !== null && this.type !== type) {
            console.error("this Broadcast has binding");
        }
        this.type = type;
    };
    MessageBroadcast.prototype.receive = function (data) {
        var _this = this;
        this.dom.dispatchEvent(new CustomEvent('receive', {
            detail: { target: _this, name: "receive", data: data },
            cancelable: true
        }));
    };
    MessageBroadcast.prototype.registe = function (receiver) {
        if (this.type !== MessageBroadcast.Type.RECEICE) {
            console.error("type not match");
        }
        this.dom.addEventListener('receive', function (e) {
            receiver.receive(e.detail.data);
        });
    };
    MessageBroadcast.prototype.send = function (data) {
        if (this.type !== MessageBroadcast.Type.SEND) {
            console.error("type not match");
        }
        _super.prototype.send.call(this, data);
    };
    Object.defineProperty(MessageBroadcast, "Type", {
        get: function () {
            return {
                SEND: 0,
                RECEICE: 1
            };
        },
        enumerable: false,
        configurable: true
    });
    return MessageBroadcast;
}(Broadcast));
// 广播发送者
var BroadcastSender = /** @class */ (function () {
    function BroadcastSender(name, broadcastChannel) {
        this.groupName = name;
        broadcastChannel.bindingtype(MessageBroadcast.Type.SEND);
        this.bc = broadcastChannel;
    }
    BroadcastSender.prototype.send = function (data) {
        var _this = this;
        this.bc.send({
            group: _this.groupName,
            data: data
        });
    };
    Object.defineProperty(BroadcastSender.prototype, "name", {
        get: function () {
            return this.groupName;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(BroadcastSender.prototype, "MessageBroadcast", {
        get: function () {
            return this.bc;
        },
        enumerable: false,
        configurable: true
    });
    return BroadcastSender;
}());
// 广播接收者
var BroadcastReceiver = /** @class */ (function () {
    function BroadcastReceiver(name, broadcastChannel) {
        this.groupName = name;
        this.broadcast = broadcastChannel;
        broadcastChannel.bindingtype(MessageBroadcast.Type.RECEICE);
        broadcastChannel.registe(this);
    }
    BroadcastReceiver.prototype.receive = function (data) {
        if (data.group !== this.groupName) {
            return null;
        }
        return data.data;
    };
    Object.defineProperty(BroadcastReceiver.prototype, "MessageBroadcast", {
        get: function () {
            return this.broadcast;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(BroadcastReceiver.prototype, "name", {
        get: function () {
            return this.groupName;
        },
        enumerable: false,
        configurable: true
    });
    return BroadcastReceiver;
}());
// 广播接收 进一步封装为装饰者模式
var DecoratorsBroadcastReceiver = /** @class */ (function (_super) {
    __extends(DecoratorsBroadcastReceiver, _super);
    function DecoratorsBroadcastReceiver(receiver) {
        var _this_1 = _super.call(this, receiver.name, receiver.MessageBroadcast) || this;
        _this_1.parent = receiver;
        return _this_1;
    }
    DecoratorsBroadcastReceiver.prototype.receive = function (data) {
        if (this.parent !== undefined && this.parent !== null) {
            data = this.parent.receive(data);
        }
        return data;
    };
    Object.defineProperty(DecoratorsBroadcastReceiver.prototype, "MessageBroadcast", {
        get: function () {
            return this.parent.MessageBroadcast;
        },
        enumerable: false,
        configurable: true
    });
    return DecoratorsBroadcastReceiver;
}(BroadcastReceiver));
// 广播发送 进一步封装为装饰者模式
var DecoratorsBroadcastSender = /** @class */ (function (_super) {
    __extends(DecoratorsBroadcastSender, _super);
    function DecoratorsBroadcastSender(sender) {
        var _this_1 = _super.call(this, sender.name, sender.MessageBroadcast) || this;
        _this_1.parent = sender;
        return _this_1;
    }
    DecoratorsBroadcastSender.prototype.send = function (data) {
        if (this.parent !== undefined && this.parent !== null) {
            this.parent.send(data);
        }
    };
    Object.defineProperty(DecoratorsBroadcastSender.prototype, "MessageBroadcast", {
        get: function () {
            return this.parent.MessageBroadcast;
        },
        enumerable: false,
        configurable: true
    });
    return DecoratorsBroadcastSender;
}(BroadcastSender));
// 事件发送者
var EventBroadcastSender = /** @class */ (function (_super) {
    __extends(EventBroadcastSender, _super);
    function EventBroadcastSender(sender) {
        return _super.call(this, sender) || this;
    }
    EventBroadcastSender.prototype.send = function (event) {
        var _data = {
            type: event.type,
            senderType: "event"
        };
        _super.prototype.send.call(this, _data);
    };
    return EventBroadcastSender;
}(DecoratorsBroadcastSender));
// 事件接收器
var EventBroadcastReceiver = /** @class */ (function (_super) {
    __extends(EventBroadcastReceiver, _super);
    function EventBroadcastReceiver(parent) {
        var _this_1 = _super.call(this, parent) || this;
        _this_1.dom = document.createElement("div");
        return _this_1;
    }
    EventBroadcastReceiver.prototype.receive = function (data) {
        data = _super.prototype.receive.call(this, data);
        if (data === null || data.senderType !== "event") {
            return;
        }
        ;
        this.dom.dispatchEvent(new CustomEvent(data.type));
    };
    EventBroadcastReceiver.prototype.addEventListener = function (type, listener, useCapture) {
        this.dom.addEventListener(type, listener, useCapture);
    };
    EventBroadcastReceiver.prototype.removeEventListener = function (type, listener, useCapture) {
        this.dom.removeEventListener(type, listener, useCapture);
    };
    return EventBroadcastReceiver;
}(DecoratorsBroadcastReceiver));
// 事件代理
var EventProxy = /** @class */ (function (_super) {
    __extends(EventProxy, _super);
    function EventProxy(target, sender) {
        var _this_1 = _super.call(this) || this;
        _this_1.sender = null;
        _this_1.target = null;
        _this_1.target = target;
        _this_1.sender = sender;
        return _this_1;
    }
    EventProxy.prototype.addEventListener = function (type, listener, options) {
        var _this = this;
        this.target.addEventListener(type, function () {
            _this.sender.send({ type: type });
        });
        this.target.addEventListener(type, listener, options);
    };
    return EventProxy;
}(EventTarget));
// 半双工广播 = 两条半工通道
var HalfDuplexBroadcast = /** @class */ (function (_super) {
    __extends(HalfDuplexBroadcast, _super);
    function HalfDuplexBroadcast(name) {
        var _this_1 = _super.call(this, name) || this;
        _this_1.sendBroadcast = new MessageBroadcast(name);
        _this_1.channelId = new Date().getTime() + "-" + parseInt((Math.random() * 1000).toString());
        return _this_1;
    }
    HalfDuplexBroadcast.prototype.bindingtype = function (type) {
        _super.prototype.bindingtype.call(this, MessageBroadcast.Type.RECEICE);
        this.sendBroadcast.bindingtype(MessageBroadcast.Type.SEND);
    };
    HalfDuplexBroadcast.prototype.send = function (data) {
        this.sendBroadcast.send({ channelId: this.channelId, data: data });
    };
    HalfDuplexBroadcast.prototype.receive = function (data) {
        // 防止本通道收到自己发送的消息
        if (data.channelId == this.channelId) {
            return;
        }
        data = data.data;
        _super.prototype.receive.call(this, data);
    };
    return HalfDuplexBroadcast;
}(MessageBroadcast));
var Handler = /** @class */ (function () {
    function Handler(name, pb) {
        this.Receiver = /** @class */ (function (_super) {
            __extends(class_1, _super);
            function class_1(name, broadcastChannel, handler) {
                var _this_1 = _super.call(this, name, broadcastChannel) || this;
                _this_1.handler = handler;
                return _this_1;
            }
            class_1.prototype.receive = function (data) {
                data = _super.prototype.receive.call(this, data);
                if (data.type == "request") {
                    this.handler.handleRequest(data.value);
                }
                if (data.type == "response") {
                    this.handler.handleResponse(data.value);
                }
            };
            return class_1;
        }(BroadcastReceiver));
        this.Sender = /** @class */ (function (_super) {
            __extends(class_2, _super);
            function class_2(name, broadcastChannel) {
                return _super.call(this, name, broadcastChannel) || this;
            }
            class_2.prototype.send = function (data) {
                _super.prototype.send.call(this, {
                    type: data.type,
                    value: data.value
                });
            };
            return class_2;
        }(BroadcastSender));
        this.ns = name;
        this.pb = pb;
        this.sender = new this.Sender(name, pb);
        this.receiver = new this.Receiver(name, pb, this);
    }
    Handler.prototype.handleRequest = function (data) {
        return data;
    };
    Handler.prototype.handleResponse = function (data) {
        return data;
    };
    Handler.prototype.request = function (data) {
        this.sender.send({ value: data, type: "request" });
    };
    Object.defineProperty(Handler.prototype, "broadcast", {
        get: function () {
            return this.pb;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(Handler.prototype, "name", {
        get: function () {
            return this.ns;
        },
        enumerable: false,
        configurable: true
    });
    return Handler;
}());
// 封装为装饰器模式
var DecoratorsHandler = /** @class */ (function (_super) {
    __extends(DecoratorsHandler, _super);
    function DecoratorsHandler(handler) {
        if (handler === void 0) { handler = null; }
        var _this_1 = _super.call(this, handler.name, handler.broadcast) || this;
        _this_1.parent = null;
        _this_1.parent = handler;
        return _this_1;
    }
    DecoratorsHandler.prototype.handleRequest = function (data) {
        if (this.parent !== null) {
            data = this.parent.handleRequest(data);
        }
        return _super.prototype.handleRequest.call(this, data);
    };
    DecoratorsHandler.prototype.handleResponse = function (data) {
        if (this.parent !== null) {
            data = this.parent.handleResponse(data);
        }
        return _super.prototype.handleResponse.call(this, data);
    };
    return DecoratorsHandler;
}(Handler));
// 方法执行器用于保存方法和调用环境
var Executor = /** @class */ (function () {
    function Executor(func, env) {
        this.func = func;
        this.env = env;
    }
    Executor.prototype.exec = function () {
        var param = [];
        for (var _i = 0; _i < arguments.length; _i++) {
            param[_i] = arguments[_i];
        }
        this.func.apply(this.env, param);
    };
    return Executor;
}());
var PromiseExecutor = /** @class */ (function () {
    function PromiseExecutor(resolve, rejected, env) {
        this.resolveExecutor = new Executor(resolve, env);
        this.rejectedExecutor = new Executor(rejected, env);
    }
    PromiseExecutor.prototype.resolve = function (param) {
        this.resolveExecutor.exec(param);
    };
    PromiseExecutor.prototype.rejected = function (param) {
        this.rejectedExecutor.exec(param);
    };
    return PromiseExecutor;
}());
// 对象代理处理器
var ObjectProxyHandler = /** @class */ (function (_super) {
    __extends(ObjectProxyHandler, _super);
    function ObjectProxyHandler(parent) {
        if (parent === void 0) { parent = null; }
        var _this_1 = _super.call(this, parent) || this;
        _this_1.promises = {};
        _this_1.no = 0;
        _this_1.bindings = [];
        return _this_1;
    }
    ObjectProxyHandler.prototype.handleRequest = function (data) {
        data = _super.prototype.handleRequest.call(this, data);
        // {type:"method/property", params:[], attr: "", value: "", error: ""}
        var id = data.data.id;
        var bind = this.bindings[id];
        // 收到自己未绑定的id，可能是其他通道的调用，此处不处理
        if (bind === null || bind === undefined) {
            return;
        }
        try {
            var r = bind.exec(data.data);
            data.value = r;
        }
        catch (e) {
            data.value = undefined;
            data.error = e;
        }
        this.sender.send({ value: data, type: "response" });
    };
    ObjectProxyHandler.prototype.handleResponse = function (data) {
        data = _super.prototype.handleResponse.call(this, data);
        // 没有相应的请求，可能是其他通道请求的响应
        if (this.promises[data.no] === null || this.promises[data.no] === undefined) {
            return;
        }
        // {type:"method/property", params:[], attr: "", value: "", error: ""}
        if (data.error === null || data.error === undefined) {
            this.promises[data.no].resolve(data.value);
            return;
        }
        this.promises[data.no].rejected(data.error);
    };
    ObjectProxyHandler.prototype.request = function (data) {
        var _this_1 = this;
        var _this = this;
        var _no = 'p_' + this.no;
        var r = new Promise(function (s, e) {
            var exec = new PromiseExecutor(s, e, _this_1);
            _this.promises[_no] = exec;
        });
        _super.prototype.request.call(this, {
            no: _no,
            data: data
        });
        this.no++;
        return r;
    };
    ObjectProxyHandler.prototype.binding = function (id, binding) {
        this.bindings[id] = binding;
    };
    return ObjectProxyHandler;
}(DecoratorsHandler));
var ObjectProxyBinding = /** @class */ (function () {
    function ObjectProxyBinding(binding) {
        this.binding = binding;
    }
    // {type:"method/property", params:[], attr: "", value: ""}
    ObjectProxyBinding.prototype.exec = function (data) {
        if (data.type === "method") {
            if (this.binding[data.attr] === undefined || this.binding[data.attr] === null) {
                throw "Cannot read properties of undefined (reading '" + data.attr + "')";
            }
            return this.binding[data.attr].apply(this.binding, data.params);
        }
        if (data.type === "property") {
            if (data.value === null) {
                return this.binding[data.attr];
            }
            else {
                this.binding[data.attr] = data.value;
                return undefined;
            }
        }
    };
    return ObjectProxyBinding;
}());
var ObjectProxy = /** @class */ (function () {
    function ObjectProxy(id, handler) {
        this.id = null;
        this.handler = null;
        this.id = id;
        this.handler = handler;
    }
    ObjectProxy.prototype.addProperty = function () {
        var properties = [];
        for (var _i = 0; _i < arguments.length; _i++) {
            properties[_i] = arguments[_i];
        }
        var _this = this;
        var _loop_1 = function () {
            var property = properties[i];
            Object.defineProperty(_this, property, {
                get: function () {
                    return _this.handler.request({ params: "", id: _this.id, type: "property", attr: property, value: null });
                },
                set: function (s) {
                    _this.handler.request({ params: "", id: _this.id, type: "property", attr: property, value: s });
                }
            });
        };
        for (var i = 0, l = properties.length; i < l; i++) {
            _loop_1();
        }
    };
    ObjectProxy.prototype.addMethod = function () {
        var methods = [];
        for (var _i = 0; _i < arguments.length; _i++) {
            methods[_i] = arguments[_i];
        }
        var _this = this;
        var _loop_2 = function () {
            var method = methods[i];
            this_1[method] = function () {
                var param = [];
                for (var _i = 0; _i < arguments.length; _i++) {
                    param[_i] = arguments[_i];
                }
                return _this.handler.request({ params: param, id: _this.id, type: "method", attr: method, value: null });
            };
        };
        var this_1 = this;
        for (var i = 0, l = methods.length; i < l; i++) {
            _loop_2();
        }
    };
    return ObjectProxy;
}());
// 对象监听Handler 对request请求进行监听，触发函数
var ObjectProxyListenerHandler = /** @class */ (function (_super) {
    __extends(ObjectProxyListenerHandler, _super);
    function ObjectProxyListenerHandler(parent) {
        if (parent === void 0) { parent = null; }
        return _super.call(this, parent) || this;
    }
    ObjectProxyListenerHandler.prototype.handleRequest = function (data) {
        // {type:"method/property", params:[], attr: "", value: "", error: ""}
        var id = data.data.id;
        var bind = this.bindings[id];
        // 收到自己未绑定的id，可能是其他通道的调用，此处不处理
        if (bind === null || bind === undefined) {
            return;
        }
        // 因为是监听，出发相应的方法，若是属性则触发同名的方法
        data.type = "method";
        bind.exec(data.data);
    };
    return ObjectProxyListenerHandler;
}(ObjectProxyHandler));
